<?php

/**
 *
 * @package    mahara
 * @subpackage artefact-feedback
 * @author     laurent.opprecht@gmail.com
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL
 * @copyright  (C) 2011 University of Geneva http://www.unige.ch/
 *
 */
defined('INTERNAL') || die();

require_once(dirname(__FILE__) . '/form/add_parentfeedback.php');
require_once(dirname(__FILE__) . '/form/delete_parentfeedback.php');
require_once(dirname(__FILE__) . '/ui/feedback_table.class.php');
require_once(dirname(__FILE__) . '/util/code_util.class.php');
require_once(dirname(__FILE__) . '/patch/feedback_patch.class.php');

class PluginArtefactFeedback extends PluginArtefact
{

    public static function get_headers()
    {
        $headers = array();
        $javascript = get_config('wwwroot') . 'artefact/feedback/js/feedback.js';
        $javascript = '<script type="text/javascript" src="' . $javascript . '"></script>';
        $headers[] = $javascript;

        $style = get_config('wwwroot') . 'artefact/feedback/theme/raw/static/style/style.css';
        $style = '<link rel="stylesheet" type="text/css" href="' . $style . '">';
        $headers[] = $style;
        return $headers;
    }

    public static function get_artefact_types()
    {
        return array(
            'feedback',
        );
    }

    public static function get_block_types()
    {
        return array();
    }

    public static function get_plugin_name()
    {
        return 'feedback';
    }

    public static function menu_items()
    {
        return array();
    }

    public static function get_event_subscriptions()
    {
        return array();
    }

    public static function get_activity_types()
    {
        return array();
    }

    public static function postinst($prevversion)
    {
        FeedbackPatch::apply();
        return true;
    }

    public static function view_export_extra_artefacts($viewids)
    {
        $artefacts = array();
        //@TODO:
        return $artefacts;
    }

    public static function artefact_export_extra_artefacts($artefactids)
    {
        $artefacts = array();
        //@TODO:
        return $artefacts;
    }

//    /**
//     * Autoload function for the plugin.
//     * @param string $class_name 
//     */
//    public static function autoload($class_name){
//        if($class_name == 'BlockInstance'){
//            require_once dirname(__FILE__) . '/patch/lib2.php';
//            return true;
//        }
//        return false;
//    }
//    
//    public static function register_autoload(){
//        return spl_autoload_register(array(__CLASS__, 'autoload'));
//    }
//    
//    public static function unregister_autoload(){
//        return spl_autoload_unregister(array(__CLASS__, 'autoload'));
//    }
}

class ArtefactTypeFeedback extends ArtefactType
{
    const TABLE_NAME = 'artefact_feedback';

    const DEFAULT_LIMIT = 3;

    public static function get_limit($value=null)
    {
        $value = (int) $value;
        $result = $value ? $value : self::DEFAULT_LIMIT;
        //@todo: fetch the value from configuration
        return $result;
    }

    public static function get_id($object)
    {
        return is_object($object) && !is_null($object) ? $object->get('id') : (int) $object;
    }

    public static function get_view_id($object=null)
    {
        if (is_null($object))
        {
            global $view;
            return self::get_id($view);
        }
        else
        {
            return self::get_id($object);
        }
    }

    public static function is_active()
    {
        return get_field('artefact_installed', 'active', 'name', 'feedback');
    }

    private static $allow_copy_feedbacks = false;

    /**
     * If true then feedbacks can be copied. Typically when a view is copied. If false then feedbacks should not be copied.
     *
     * @return bool
     */
    public static function allow_copy_feedbacks()
    {
        return self::$allow_copy_feedbacks;
    }

    public static function allow_copy_feedbacks_on()
    {
        self::$allow_copy_feedbacks = true;
    }

    public static function allow_copy_feedbacks_off()
    {
        self::$allow_copy_feedbacks = false;
    }

    private static $allow_notification = true;

    /**
     * If true then notification is allowed. If false not. Typically when a feedback is copied notification is disabled.
     *
     * @return bool
     */
    public static function allow_notification()
    {
        return self::$allow_notification;
    }

    public static function allow_notification_on()
    {
        self::$allow_notification = true;
    }

    public static function allow_notification_off()
    {
        self::$allow_notification = false;
    }

    /**
     * Returns true if feedback footers are to be displayed on the current view. False otherwise. That is returns false for "DASBOARD" and "PROFILE" views.
     * 
     * @global View $view
     * @return bool
     */
    public static function display_footer()
    {
        global $view;
        if (!self::is_active())
        {
            return false;
        }
        $type = $view->get('type');
        if ($type == 'dashboard' || $type == 'profile')
        {
            return false;
        }
        return true;
    }

    /**
     * Return true if a user can edit feedbacks. False otherwise.
     *
     * @param View $view
     */
    public static function can_edit($can_edit)
    {
        global $view;
        return (bool) $view->get('allowcomments');
    }

    /**
     * Returns true if the logged in user is the owner of $view_id. Returns false otherwise.
     *
     * @global User $USER
     * @global View $view
     * @param int $view_id
     * @return bool
     */
    public static function is_view_owner($view_id=null)
    {
        global $USER;
        global $view;

        $the_view = is_null($view_id) ? $view : new View($view_id);
        $view_owner_id = $the_view ? $the_view->get('owner') : false;
        $user_id = self::get_id($USER);
        $result = $user_id != 0 && $user_id == $view_owner_id;
        return $result;
    }

    protected $artefact;
    protected $to;
    protected $totype;
    protected $private;
    protected $deletedtime;
    protected $deletedby;

    public function __construct($id = 0, $data = null)
    {
        parent::__construct($id, $data);

        if ($this->id && ($extra = get_record(self::TABLE_NAME, 'artefact', $this->id)))
        {
            foreach ($extra as $name => $value)
            {
                if (property_exists($this, $name))
                {
                    $this->{$name} = $value;
                }
            }
        }
    }

    public function commit()
    {
        global $USER;
        if (empty($this->dirty))
        {
            return;
        }

        $new = empty($this->id);


        if (!$this->get('owner'))
        {
            $this->set('owner', $USER->get('id'));
        }

        db_begin();
        parent::commit();

        $data = (object) array(
                    'artefact' => $this->get('id'),
                    'to' => $this->get('to'),
                    'totype' => $this->get('totype'),
                    'private' => $this->get('private'),
                    'deletedtime' => $this->get('deletedtime'),
                    'deletedby' => $this->get('deletedby'),
        );

        if ($new)
        {
            insert_record(self::TABLE_NAME, $data);
        }
        else
        {
            update_record(self::TABLE_NAME, $data, 'artefact');
        }
        db_commit();
        $this->dirty = false;

        if (self::allow_notification())
        {
            $description = $this->get('description');
            $description = trim(strip_tags(html2text($description, true)));
            $author_id = $this->get('author');
            $author = new User();
            $author->find_by_id($author_id);
            $author = display_default_name($author);

            $block = new BlockInstance($this->get('to'));
            $owner = $block->get_view()->get('owner');

            $message = new StdClass;
            $message->users = array($owner);
            $message->subject = get_string('feedbackcreatedsubject', 'artefact.feedback', $author);
            $message->message = get_string('feedbackcreatedmessage', 'artefact.feedback', $description);

            require_once('activity.php');
            activity_occurred('maharamessage', $message);
        }
    }

    public static function is_singular()
    {
        return false;
    }

    public static function get_icon($options=null)
    {
        global $THEME;
        return $THEME->get_url('images/feedback.gif', false, 'artefact/feedback');
    }

    public function delete()
    {
        if (empty($this->id))
        {
            return;
        }

        $description = $this->get('description');
        $author = $this->get('author');

        db_begin();
        //$this->detach();
        delete_records(self::TABLE_NAME, 'artefact', $this->id);
        parent::delete();
        db_commit();

        if (self::allow_notification())
        {
            //log activity
            $description = $this->get('description');
            $description = trim(strip_tags(html2text($description, true)));

            $block = new BlockInstance($this->get('to'));
            $owner = $block->get_view()->get('owner');

            $message = new StdClass;
            $message->users = array($owner);
            $message->subject = get_string('feedbackdeletedsubject', 'artefact.feedback');
            $message->message = get_string('feedbackdeletedmessage', 'artefact.feedback', $description);


            require_once('activity.php');
            activity_occurred('maharamessage', $message);
        }
    }

    public static function bulk_delete($artefactids)
    {
        if (empty($artefactids))
        {
            return;
        }

        $idstr = join(',', array_map('intval', $artefactids));

        db_begin();
        delete_records_select(self::TABLE_NAME, 'artefact IN (' . $idstr . ')');
        parent::bulk_delete($artefactids);
        db_commit();
    }

    /**
     * Copy feedbacks from $from to $to. 
     *
     * @param int|object $from  the object to copy feedbacks from
     * @param int|object $to    the object to copy feedbacks to
     * @param bool $force       if true the function is always executed. If false the function is only executed if the allow_copy_feedback parameter is turned on.
     *
     * @return bool returns true on success/if the function was executed, false otherwise.
     */
    public static function copy_feebaks($from, $to, $force = false)
    {
        if (!$force && !self::allow_copy_feedbacks())
        {
            return false;
        }
        $feedbacks = self::get_feedbacks_onparent($from, true, 1000, 0);
        if (empty($feedbacks))
        {
            return false;
        }
        self::allow_notification_off();
        $toid = self::get_id($to);
        db_begin();
        foreach ($feedbacks as $feedback)
        {
            $data = (object) array();

            $data->to = $toid;
            $data->totype = $feedback->totype;
            $data->deletedby = $feedback->deletedby;
            $data->deletedtime = $feedback->deletedtime;
            $data->private = $feedback->private;
            $data->description = $feeback->description;

            $new = new self(null, $data);
            $new->commit();
        }
        db_commit();
        self::allow_copy_feedbacks_on();
        return true;
    }

    public static function delete_feedbacks_onparent($parentid)
    {
        if (empty($parentid))
        {
            return;
        }
        $ids = get_column(self::TABLE_NAME, 'artefact', 'to', $parentid);
        self::bulk_delete($ids);
    }

    public static function get_links($id)
    {
        return array(
            '_default' => get_config('wwwroot') . 'artefact/feedback/view.php?id=' . $id,
        );
    }

    public function can_have_attachments()
    {
        return false;
    }

    public static function get_feedbacks_onparent($parent=null, $show_private = null, $limit=10, $offset=0)
    {
        global $USER;
        global $view;
        $parentid = self::get_id($parent);

        $show_private = is_null($show_private) ? self::is_view_owner() : $show_private;
        $user_id = self::get_id($USER);

        $where = 'c.to=' . (int) $parentid;
        $where .= $show_private ? '' : ' AND (c.private = 0 OR a.author=' . $user_id . ')';

        $data = get_records_sql_assoc('
                SELECT
                    a.id, a.author, a.authorname, a.ctime, a.mtime, a.description,
                    c.private, c.deletedby, c.deletedtime, c.to, c.totype,
                    u.username, u.firstname, u.lastname, u.preferredname, u.email, u.staff, u.admin,
                    u.deleted, u.profileicon
                FROM {artefact} a
                    INNER JOIN {' . self::TABLE_NAME . '} c ON a.id = c.artefact
                    LEFT JOIN {usr} u ON a.author = u.id
                WHERE ' . $where . '
                ORDER BY a.ctime DESC', array(), $offset, $limit);

        if ($data)
        { //$data can equals to false, if it is the case foreach will issue a warning
            $view_owner = $view ? $view->get('owner') : false;
            $authors = array(); //cache
            foreach ($data as &$item)
            {
                $item->author_id = $item->author;
                $item->can_delete = $item->author_id == $view_owner || $item->author_id == $user_id;
                $item->delete_form = $item->can_delete ? delete_parentfeedback_form::create($item->id) : false;

                if ($item->author)
                {
                    if (!isset($authors[$item->author]))
                    {
                        $authors[$item->author] = (object) array(
                                    'id' => $item->author,
                                    'username' => $item->username,
                                    'firstname' => $item->firstname,
                                    'lastname' => $item->lastname,
                                    'preferredname' => $item->preferredname,
                                    'email' => $item->email,
                                    'staff' => $item->staff,
                                    'admin' => $item->admin,
                                    'deleted' => $item->deleted,
                                    'profileicon' => $item->profileicon,
                        );
                    }
                    $item->author = $authors[$item->author];
                }
                $format = get_string('strftimedaydate');
                $item->time = strftime($format, strtotime($item->ctime));
            }
        }
        return $data;
    }

    public static function count_feedbacks_onparent($parent=null, $show_private = null)
    {
        global $USER;
        $parentid = is_object($parent) ? $parent->get('id') : (int) $parent;
        $user_id = self::get_id($USER);

        $show_private = is_null($show_private) ? self::is_view_owner() : $show_private;

        $where = 'c.to=' . (int) $parentid;
        $where .= $show_private ? '' : ' AND (c.private = 0 OR a.author=' . $user_id . ')';

        $sql = 'SELECT COUNT(a.id)
                FROM {artefact} a
                    INNER JOIN {' . self::TABLE_NAME . '} c ON a.id = c.artefact
                WHERE ' . $where;

        $result = get_records_sql_array($sql, array());
        return reset(reset($result));
    }

    public static function build_footer($parent)
    {
        if (!self::display_footer($parent))
        {
            return '';
        }

        static $index = 1;
        $parent_id = self::get_id($parent);
        $view_id = self::get_view_id();
        $view_private = self::is_view_owner();
        $can_edit = self::can_edit($parent);

        $data = new stdClass();
        $data->parent_id = $parent_id;
        $data->count = self::count_feedbacks_onparent($parent, $view_private);
        $data->data = self::get_feedbacks_onparent($parent, $view_private, 3);
        $data->toid = $parent_id;
        $table_id = FeedbackTable::get_table_id($parent_id);

        $smarty = smarty();
        $smarty->assign_by_ref('data', $data->data);
        $smarty->assign('count', $data->count);
        $smarty->assign('parent_id', $data->parent_id);
        $smarty->assign('table_id', $table_id);
        $smarty->assign('view_id', $view_id);
        $smarty->assign('index', $index++);
        $smarty->assign('can_edit', $can_edit);
        $data->footer = $smarty->fetch('artefact:feedback:feedback_footer.tpl');

        return $data->footer;
    }

    public function render_self()
    {
        return clean_html($this->get('description'));
    }

    public function exportable()
    {
        return empty($this->deletedtime);
    }

    public function get_view_url($view, $showcomment=true)
    {
        $viewid = is_object($view) ? $view->get('id') : (int) $view;
        $result = get_config('wwwroot') . 'view/view.php?id=' . $viewid;
        if ($showcomment)
        {
            $result .= '&showcomment=' . $this->get('id');
        }
        return $result;
    }

}
